package zqueue

import (
	"fmt"
	"sync"
)

type ZQueue struct {
	topic string
	first *node
	last  *node
	n     int
	mx    sync.Mutex
}

type node struct {
	seq   int
	value interface{}
	next  *node
}

func (q *node) String() string {
	return fmt.Sprintf("ZNode seq(%d) value %v next %v", q.seq, q.value, q.next)
}

func (q *node) Seq() int {
	return q.seq
}

func NewQueue(topic string) *ZQueue {
	return &ZQueue{topic: topic}
}

func (q *ZQueue) String() string {
	return fmt.Sprintf("ZQueue topic: %s len: %d first %s next %s", q.topic, q.n, q.first, q.last)
}

func (q *ZQueue) IsEmpty() bool {
	return q.n == 0
}

func (q *ZQueue) Size() int {
	return q.n
}

func (q *ZQueue) Push(item interface{}) {
	q.mx.Lock()
	defer q.mx.Unlock()

	oldest := q.last
	seq := q.n + 1
	q.last = &node{seq: seq}
	q.last.value = item
	q.last.next = nil
	if q.IsEmpty() {
		q.first = q.last
	} else {
		oldest.next = q.last
	}
	q.n++
}

func (q *ZQueue) Next() (seq int, value interface{}) {
	q.mx.Lock()
	defer q.mx.Unlock()

	if q.IsEmpty() {
		return 0, nil
	}
	seq = q.first.seq
	item := q.first.value
	q.first = q.first.next
	if q.IsEmpty() {
		q.last = nil
	}
	q.n--
	return seq, item
}
